﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using Autodesk.Revit.ApplicationServices;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using YJKArchMethodLibrary.Utils;
using YJKElementFinish.ColumnSurface.DataDefinition;
using YJKElementFinish.ColumnSurface.Managers;
using YJKElementFinish.MultiWallEdit.Forms;

namespace YJKElementFinish.MultiWallEdit.Controller
{
	public class WallMergeController
	{
		public WallMergeController(ExternalCommandData cmdData)
		{
			this.m_ComdData = cmdData;
			this.m_UIApp = cmdData.Application;
			this.m_UIDoc = this.m_UIApp.ActiveUIDocument;
			this.m_App = this.m_UIApp.Application;
			this.m_Doc = this.m_UIDoc.Document;
		}

		public Result Merge()
		{
			List<Wall> selWalls = new List<Wall>();
			if (!WallCommon.SelectWalls(this.m_UIDoc, ref selWalls))
			{
				return Autodesk.Revit.UI.Result.Cancelled;
			}
			WallGroupingController wallGroupingController = new WallGroupingController(this.m_ComdData);
			List<List<Wall>> list = new List<List<Wall>>();
			List<List<Wall>> list2 = new List<List<Wall>>();
			List<Wall> list3 = new List<Wall>();
			wallGroupingController.WallGrouping(selWalls, ref list, ref list2, ref list3);
			List<List<Wall>> list4 = new List<List<Wall>>();
			list4.AddRange(list);
			list4.AddRange(list2);
			List<List<WallType>> list5 = new List<List<WallType>>();
			List<KeyValuePair<int, bool>> list6 = new List<KeyValuePair<int, bool>>();
			wallGroupingController.GetWallTypeGroup(list4, ref list5, ref list6);
			if (list5.Count == 0)
			{
				MessageBox.Show("无可合并的成组多墙", "盈建科提示");
				return Autodesk.Revit.UI.Result.Cancelled;
			}
			WallTypeMergeForm wallTypeMergeForm = new WallTypeMergeForm(list5, this.m_Doc);
			if (wallTypeMergeForm.ShowDialog() != DialogResult.OK)
			{
				return Autodesk.Revit.UI.Result.Cancelled;
			}
			List<List<List<WallTypeLayerInfos>>> combinationInfosByGroup = wallTypeMergeForm.GetCombinationInfosByGroup();
			List<List<List<WallTypeLayerInfos>>> list7 = new List<List<List<WallTypeLayerInfos>>>();
			int i;
			for (i = 0; i < list.Count; i++)
			{
				list7.Add(combinationInfosByGroup[list6[i].Key]);
			}
			List<List<List<WallTypeLayerInfos>>> list8 = new List<List<List<WallTypeLayerInfos>>>();
			while (i < list.Count + list2.Count)
			{
				list8.Add(combinationInfosByGroup[list6[i].Key]);
				i++;
			}
			this.MergeLinearWall(list, list7);
			this.MergeArcWall(list2, list8);
			return Autodesk.Revit.UI.Result.Succeeded;
		}

		private void MergeLinearWall(List<List<Wall>> linearWalls, List<List<List<WallTypeLayerInfos>>> combinationInfosByGroup)
		{
			for (int i = 0; i < linearWalls.Count; i++)
			{
				List<Wall> list = linearWalls[i];
				List<List<WallTypeLayerInfos>> list2 = combinationInfosByGroup[i];
				int j = 0;
				int num = 0;
				while (j < list2.Count)
				{
					List<WallTypeLayerInfos> list3 = list2[j];
					List<Wall> range = list.GetRange(num, list3.Count);
					this.MergeSingleGroupWall(range);
					num += list3.Count;
					j++;
				}
			}
		}

		private bool MergeSingleGroupWall(List<Wall> walls)
		{
			Transaction transaction = null;
			try
			{
				transaction = new Transaction(this.m_Doc);
				transaction.Start("merge wall");
				Wall wall = WallCommon.FindMainWall(walls, this.m_Doc);
				if (wall == null)
				{
					transaction.RollBack();
					return false;
				}
				bool hasFlip = this.HasFlipWallGroup(wall, ref walls);
				List<CompoundStructureLayer> layers = new List<CompoundStructureLayer>();
				double width = 0.0;
				List<ElementId> list = new List<ElementId>();
				this.GetMergeInfo(walls, hasFlip, ref list, ref layers, ref width);
				string typeNameByLayers = WallTypeManager.GetTypeNameByLayers(layers, this.m_Doc);
				WallUtils.DisallowWallJoinAtEnd(wall, 0);
				WallUtils.DisallowWallJoinAtEnd(wall, 1);
				WallType wallType = WallTypeManager.GetWallType(typeNameByLayers, wall.WallType, layers, this.m_Doc, false);
				XYZ xyz = XYZ.BasisY * 100.0;
				Wall wall2 = null;
				if (wallType != null)
				{
					ICollection<ElementId> source = ElementTransformUtils.CopyElement(this.m_Doc, wall.Id, xyz);
					wall2 = (this.m_Doc.GetElement(source.ElementAt(0)) as Wall);
					if (wall2.Flipped)
					{
						wall2.Flip();
					}
					Curve curve = null;
					this.GetOffsetLocationWithMergedWall(wall, walls, width, xyz, ref curve);
					(wall2.Location as LocationCurve).Curve = curve;
					WallUtils.AllowWallJoinAtEnd(wall2, 0);
					WallUtils.AllowWallJoinAtEnd(wall2, 1);
				}
				transaction.Commit();
				transaction = new Transaction(this.m_Doc);
				transaction.Start("delete old walls");
				foreach (ElementId elementId in list)
				{
					Wall wall3 = this.m_Doc.GetElement(elementId) as Wall;
					if (wall3 != null)
					{
						WallUtils.DisallowWallJoinAtEnd(wall3, 0);
						WallUtils.DisallowWallJoinAtEnd(wall3, 1);
					}
				}
				this.m_Doc.Delete(list);
				wall2.WallType = wallType;
				ElementTransformUtils.MoveElement(this.m_Doc, wall2.Id, -xyz);
				transaction.Commit();
			}
			catch (Exception)
			{
				if (transaction != null)
				{
					transaction.RollBack();
				}
				return false;
			}
			return true;
		}

		private void GetOffsetLocationWithMergedWall(Wall kernelWall, List<Wall> walls, double width, XYZ vtMove, ref Curve newCenterLine)
		{
			Curve curve = (kernelWall.Location as LocationCurve).Curve;
			if (curve.GetType() == typeof(Arc))
			{
				this.GetOffsetLocationWithMergedArcWall(curve, walls, width, vtMove, ref newCenterLine);
				return;
			}
			this.GetOffsetLocationWithMergedLinearWall(curve, walls, width, vtMove, ref newCenterLine);
		}

		private void GetOffsetLocationWithMergedLinearWall(Curve kernelWallCenterCurve, List<Wall> walls, double width, XYZ vtMove, ref Curve newCenterLine)
		{
			XYZ endPoint = kernelWallCenterCurve.GetEndPoint(0);
			XYZ endPoint2 = kernelWallCenterCurve.GetEndPoint(1);
			XYZ xyz = null;
			double num = 0.0;
			for (int i = 0; i < walls.Count; i++)
			{
				Wall wall = walls[i];
				Curve curve = (wall.Location as LocationCurve).Curve;
				curve.GetEndPoint(0);
				XYZ xyz2 = Geometry.CalculateFootPoint((Line)curve, endPoint);
				double num2 = wall.Width / 2.0;
				double num3 = endPoint.DistanceTo(xyz2) + num2;
				if (Geometry.LessThan(num, num3))
				{
					num = num3;
					xyz = xyz2;
				}
			}
			XYZ xyz3 = (xyz - endPoint).Normalize();
			double num4 = width / 2.0;
			double num5 = num - num4;
			XYZ xyz4 = endPoint + xyz3 * num5;
			XYZ xyz5 = endPoint2 + xyz3 * num5;
			newCenterLine = Line.CreateBound(xyz4 + vtMove, xyz5 + vtMove);
		}

		private void GetMergeInfo(List<Wall> walls, bool hasFlip, ref List<ElementId> oldWallIds, ref List<CompoundStructureLayer> layers, ref double width)
		{
			foreach (Wall wall in walls)
			{
				CompoundStructure compoundStructure = wall.WallType.GetCompoundStructure();
				List<CompoundStructureLayer> list = compoundStructure.GetLayers().ToList<CompoundStructureLayer>();
				if (wall.Flipped)
				{
					list.Reverse();
				}
				layers.AddRange(list);
				width += wall.Width;
				oldWallIds.Add(wall.Id);
				WallUtils.DisallowWallJoinAtEnd(wall, 0);
				WallUtils.DisallowWallJoinAtEnd(wall, 1);
			}
		}

		private bool HasFlipWallGroup(Wall kernelWall, ref List<Wall> walls)
		{
			Curve curve = (kernelWall.Location as LocationCurve).Curve;
			if (curve.GetType() == typeof(Arc))
			{
				return this.HasFlipArcWallGroup(curve, ref walls);
			}
			return this.HasFlipLinearWallGroup(curve, ref walls);
		}

		private bool HasFlipLinearWallGroup(Curve kernelWallCenterCurve, ref List<Wall> walls)
		{
			LocationCurve locationCurve = walls[0].Location as LocationCurve;
			Line line = locationCurve.Curve as Line;
			LocationCurve locationCurve2 = walls[walls.Count - 1].Location as LocationCurve;
			Line line2 = locationCurve2.Curve as Line;
			XYZ endPoint = line2.GetEndPoint(0);
			XYZ xyz = Geometry.CalculateFootPoint(line, endPoint);
			XYZ pt = (endPoint - xyz).Normalize();
			Line line3 = kernelWallCenterCurve as Line;
			XYZ pt2 = Geometry.RotateTo(line3.Direction, Math.PI*.5, XYZ.BasisZ);
			if (Geometry.IsEqual(pt, pt2))
			{
				walls.Reverse();
				return false;
			}
			return true;
		}

		private void MergeArcWall(List<List<Wall>> arcWalls, List<List<List<WallTypeLayerInfos>>> combinationInfosByGroup)
		{
			for (int i = 0; i < arcWalls.Count; i++)
			{
				List<Wall> list = arcWalls[i];
				List<List<WallTypeLayerInfos>> list2 = combinationInfosByGroup[i];
				int j = 0;
				int num = 0;
				while (j < list2.Count)
				{
					List<WallTypeLayerInfos> list3 = list2[j];
					List<Wall> range = list.GetRange(num, list3.Count);
					this.MergeSingleGroupWall(range);
					num += list3.Count;
					j++;
				}
			}
		}

		private void GetOffsetLocationWithMergedArcWall(Curve kernelWallCenterCurve, List<Wall> walls, double width, XYZ vtMove, ref Curve newCenterLine)
		{
			Arc arc = kernelWallCenterCurve as Arc;
			XYZ endPoint = arc.GetEndPoint(0);
			XYZ endPoint2 = arc.GetEndPoint(1);
			XYZ center = arc.Center;
			XYZ xyz = Geometry.CalculatMidPoint(endPoint, endPoint2, center, arc.Normal);
			XYZ xyz2 = null;
			double num = 0.0;
			for (int i = 0; i < walls.Count; i++)
			{
				Wall wall = walls[i];
				Curve curve = (wall.Location as LocationCurve).Curve;
				curve.GetEndPoint(0);
				XYZ xyz3 = Geometry.CalculateFootPoint((Arc)curve, endPoint);
				double num2 = wall.Width / 2.0;
				double num3 = endPoint.DistanceTo(xyz3) + num2;
				if (Geometry.LessThan(num, num3))
				{
					num = num3;
					xyz2 = xyz3;
				}
			}
			double num4 = width / 2.0;
			double num5 = num - num4;
			XYZ xyz4 = endPoint - (endPoint - center).Normalize() * num5;
			XYZ xyz5 = endPoint2 - (endPoint2 - center).Normalize() * num5;
			XYZ xyz6 = xyz - (xyz - center).Normalize() * num5;
			XYZ pt = (xyz2 - endPoint).Normalize();
			if (Geometry.IsEqual(pt, (endPoint - center).Normalize()))
			{
				xyz4 = endPoint + (endPoint - center).Normalize() * num5;
				xyz5 = endPoint2 + (endPoint2 - center).Normalize() * num5;
				xyz6 = xyz + (xyz - center).Normalize() * num5;
			}
			newCenterLine = Arc.Create(xyz4 + vtMove, xyz5 + vtMove, xyz6 + vtMove);
		}

		private bool HasFlipArcWallGroup(Curve kernelWallCenterCurve, ref List<Wall> walls)
		{
			LocationCurve locationCurve = walls[0].Location as LocationCurve;
			Arc arc = locationCurve.Curve as Arc;
			LocationCurve locationCurve2 = walls[walls.Count - 1].Location as LocationCurve;
			Arc arc2 = locationCurve2.Curve as Arc;
			XYZ endPoint = arc2.GetEndPoint(0);
			XYZ xyz = Geometry.CalculateFootPoint(arc, endPoint);
			XYZ pt = (endPoint - xyz).Normalize();
			Arc arc3 = kernelWallCenterCurve as Arc;
			XYZ xyz2 = (endPoint - arc3.Center).Normalize();
			if (Geometry.IsEqual(arc3.Normal, XYZ.BasisZ))
			{
				xyz2 = -xyz2;
			}
			if (Geometry.IsEqual(pt, xyz2))
			{
				walls.Reverse();
				return false;
			}
			return true;
		}

		private ExternalCommandData m_ComdData;

		private UIApplication m_UIApp;

		private UIDocument m_UIDoc;

		private Autodesk.Revit.ApplicationServices.Application m_App;

		private Document m_Doc;
	}
}
